package com.demo.spring.autowird;

import java.lang.reflect.Method;

import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.StandardEnvironment;

public class Autowired底层演示3 {
	
	public static void main(String[] args) throws Throwable {
		// GenericApplicationContext是一个干净的容器
		GenericApplicationContext context = new GenericApplicationContext();
		context.registerBeanDefinition("bean2", new AnnotatedGenericBeanDefinition(Bean2.class));
		context.registerBeanDefinition("bean3", new AnnotatedGenericBeanDefinition(Bean3.class));
		
		// 用于解析String等类型的属性
		context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		// 内嵌值解析器，用于解析${}
		context.getDefaultListableBeanFactory().addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);
		// 查找哪些属性、方法加了@Autowired，这称之为InjectionMetadata
		AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
		processor.setBeanFactory(context.getDefaultListableBeanFactory());
		
		// 手动创建bean1，此时肯定没有依赖注入
		Bean1 bean1 = new Bean1();
		System.out.println(bean1);
		Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
		findAutowiringMetadata.setAccessible(true);
		// 获取Bean1上加了@Value、@Autowired的成员变量，方法参数信息
		InjectionMetadata metadata = (InjectionMetadata)findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
		// 调用InjectionMetadata来进行依赖注入，注入时按类型查找值
		metadata.inject(bean1, "bean1", null);
		System.out.println(bean1);
	}

}
